package com.xd.core.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xd.common.constant.SysConstant;
import com.xd.common.exception.XkdException;
import com.xd.common.util.SecurityUtil;
import com.xd.core.system.dto.*;
import com.xd.core.system.entity.*;
import com.xd.core.system.mapper.SysPermissionMapper;
import com.xd.core.system.mapper.SysRoleMapper;
import com.xd.core.system.mapper.SysRolePermissionMapper;
import com.xd.core.system.mapper.SysUserRoleMapper;
import com.xd.core.system.service.ISysRoleService;
import com.xd.core.system.vo.UserAndPersVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author SJ
 * @since 2023-03-17
 */
@Service
@Slf4j
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private SysRolePermissionMapper sysRolePermissionMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addRole(InsertRoleDto insertRoleDto) {

        Integer companyId = SecurityUtil.getLoginCompanyId();
        //获取当前登录用户拥有的权限，给角色赋予权限不能超过自身权限
        List<SysPermission> sysPermission = SecurityUtil.getLoginUser().getSysPermission();
        List<Integer> collect = sysPermission.stream()
                //.filter(s -> s.getVisible().equals(SysConstant.XKD_PERMISSION_VISIBLE))//敏感权限不能赋予
                .map(SysPermission::getId).collect(Collectors.toList());
        List<Integer> menuIds = insertRoleDto.getMenuIds();
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(insertRoleDto, sysRole);
        sysRole.setCompanyId(companyId);
        Date date = new Date();
        sysRole.setCreateTime(date);
        sysRole.setUpdateTime(date);
        sysRoleMapper.insert(sysRole);
        Integer id = sysRole.getId();
        if (!CollectionUtils.isEmpty(menuIds)) {
            if (new HashSet<>(collect).containsAll(menuIds)) {//添加的权限必须是该用户拥有的权限范围
                sysRoleMapper.insertMenuIdList(companyId, id, menuIds);
            } else {
                throw new XkdException("无法添加该权限，其中部分权限不在该用户权限范围");
            }
        }
    }

    public static void main(String[] args) {
        ArrayList<Integer> old = new ArrayList<>();
//        old.add(1);
//        old.add(2);
        old.add(3);
        old.add(4);
        ArrayList<Integer> xin = new ArrayList<>();
        xin.add(3);
        xin.add(4);
        xin.add(5);

        List<Integer> missingElements = old.stream()
                .filter(e -> !xin.contains(e))
                .collect(Collectors.toList());
        System.out.println(missingElements);

        System.out.println(old);
        System.out.println(xin);
        ArrayList<Integer> userIds = new ArrayList<>();
        userIds.add(1);
        userIds.add(2);
        List<String> collect = userIds.stream().map(userId -> "permission:" + userId).collect(Collectors.toList());
        System.out.println(collect);
        List<Integer> l1 = new ArrayList<>();
        List<Integer> l2 = new ArrayList<>();
        l2.add(1);
        l2.add(2);
        l1.add(3);
        l1.addAll(l2);
        System.out.println(l1);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateRole(UpdateRoleDto updateRoleDto) {
        List<Integer> menuIds = updateRoleDto.getMenuIds();//新权限
        Integer loginCompanyId = SecurityUtil.getLoginCompanyId();
        if (updateRoleDto.getId().equals(SysConstant.SYS_ROLE_SUPER))
            throw new XkdException("无权修改平台超管");
        Integer loginUserId = SecurityUtil.getLoginUserId();
        List<Integer> collect = sysRolePermissionMapper.getPers(loginUserId);
        if (!CollectionUtils.isEmpty(menuIds)) {
            if (!new HashSet<>(collect).containsAll(menuIds)) {//添加的权限必须是该用户拥有的权限范围
                throw new XkdException("无法修改该权限，其中部分权限不在该用户权限范围");
            }
        }
//        List<Integer> collect = sysPermission.stream()
//                //.filter(s -> s.getVisible().equals(SysConstant.XKD_PERMISSION_VISIBLE))//敏感权限不能赋予
//                .map(SysPermission::getId).collect(Collectors.toList());
        /*
         * 只能修改自己企业角色
         * */
        SysRole sysRole = sysRoleMapper.selectById(updateRoleDto.getId());
        if (!loginCompanyId.equals(sysRole.getCompanyId()))
            throw new XkdException("无权修改");

        //查询老权限
        List<SysRolePermission> sysRolePermissions = sysRolePermissionMapper.selectList(new LambdaQueryWrapper<SysRolePermission>().eq(SysRolePermission::getRoleId, updateRoleDto.getId()));
        List<Integer> oldPerIds = sysRolePermissions.stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList());
        //减少的权限
        List<Integer> missingElements = oldPerIds.stream()
                .filter(e -> !menuIds.contains(e))
                .collect(Collectors.toList());

        //TODO如果修改资方 代理超管等系统角色  所有公司的这些权限都要修改
        ArrayList<Integer> roleIds = new ArrayList<>();
        roleIds.add(SysConstant.SYS_ROLE_CAPITAL_SUPER);
        roleIds.add(SysConstant.SYS_ROLE_AGENCY_SUPER);
        roleIds.add(SysConstant.SYS_ROLE_BLOC_SUPER);
        List<Integer> userIds = new ArrayList<>();
        if (roleIds.contains(updateRoleDto.getId())) {
            //清除多余权限
            //清除使用该角色的公司 包括公司下面所有角色 多余的权限
            if (!CollectionUtils.isEmpty(missingElements)) {
                List<Integer> companyIds = sysRolePermissionMapper.selectCompanyIds(updateRoleDto.getId());
                if (!CollectionUtils.isEmpty(companyIds)) {
                    //查询这些企业下使用这批权限的用户ID
                    userIds = sysRolePermissionMapper.getUsesPers(companyIds, missingElements);
                    List<Integer> userIds2 = sysRolePermissionMapper.getUserIdsByRoleId(updateRoleDto.getId());
                    userIds.addAll(userIds2);
                    System.out.println(userIds);
                    sysRolePermissionMapper.deleteDissingElements(companyIds, missingElements);
                }
            }
        } else {//不是系统角色
            //如果减少的权限不为空
            if (!CollectionUtils.isEmpty(missingElements)) {
                userIds = sysRolePermissionMapper.getUserIdsByRoleId(updateRoleDto.getId());
            }
        }

        /*
         * 修改角色权限
         * */
        SysRole role = new SysRole();
        BeanUtil.copyProperties(updateRoleDto, role);
        sysRoleMapper.updateById(role);
        sysRolePermissionMapper.delete(new LambdaQueryWrapper<SysRolePermission>().eq(SysRolePermission::getRoleId, updateRoleDto.getId()));
        sysRoleMapper.insertMenuIdList(loginCompanyId, updateRoleDto.getId(), menuIds);
        final List<Integer> finalUserIds = userIds;
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {//事务成功后执行
                try {
                    if (!CollectionUtils.isEmpty(finalUserIds)) {
                        redisTemplate.delete(finalUserIds.stream().map(userId -> "permission::" + userId).collect(Collectors.toList()));
                        log.info("删除用户权限缓存");
                    }                    // 延迟再删一次，防止并发脏写
                    CompletableFuture.runAsync(() -> {
                        try {
                            Thread.sleep(500); // 500ms
                            if (!CollectionUtils.isEmpty(finalUserIds)) {
                                redisTemplate.delete(finalUserIds.stream().map(userId -> "permission::" + userId).collect(Collectors.toList()));
                                log.info("第二次删除用户权限缓存");
                            }
                        } catch (InterruptedException e) {
                            log.error("延迟删除缓存失败", e);
                        }
                    });
                } catch (Exception e) {
                    throw new XkdException("删除权限缓存错误");
                }
            }
        });


    }

//    private void updateCacheAsync(List<UserAndPersVo> userAndPersVos) {
//        log.info("执行更新缓存权限");
//        executor.execute(() -> {
//            Map<String, LoginUser> updates = new HashMap<>();
//            for (UserAndPersVo userAndPersVo : userAndPersVos) {
//                Integer userId = userAndPersVo.getUserId();
//                String redisKey = "login:" + userId;
//                List<SysPermission> sysPermissions = userAndPersVo.getSysPermissions();
//                List<String> pers = sysPermissions.stream().map(SysPermission::getPerms).collect(Collectors.toList());
//                LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(redisKey);
//                log.info("更新缓存权限" + redisKey + loginUser);
//                if (loginUser != null) {
//                    List<SimpleGrantedAuthority> authorities = pers.stream()
//                            .map(SimpleGrantedAuthority::new)
//                            .collect(Collectors.toList());
//                    loginUser.setAuthorities(authorities);
//                    loginUser.setPermissions(pers);
//                    loginUser.setSysPermission(sysPermissions);
//                    updates.put(redisKey, loginUser);
//                }
//            }
//            if (!updates.isEmpty()) {
//                log.info("执行完毕");
//                redisTemplate.opsForValue().multiSet(updates);
//                for (String key : updates.keySet()) {
//                    redisTemplate.expire(key, 60 * 2, TimeUnit.MINUTES);
//                }
//            }
//        });
//    }
//    private void updateCacheAsync(List<UserAndPersVo> userAndPersVos) {
//        executor.execute(() -> {
//            RMap<String, LoginUser> https://swtht.haoxin-pub.com = redissonClient.getMap("loginCache");
//            for (UserAndPersVo userAndPersVo : userAndPersVos) {
//                Integer userId = userAndPersVo.getUserId();
//                String redisKey = "login:" + userId;
//                List<SysPermission> sysPermissions = userAndPersVo.getSysPermissions();
//                List<String> pers = sysPermissions.stream().map(SysPermission::getPerms).collect(Collectors.toList());
//                LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(redisKey);
//                if (loginUser != null) {
//                    List<SimpleGrantedAuthority> authorities = pers.stream()
//                            .map(SimpleGrantedAuthority::new)
//                            .collect(Collectors.toList());
//                    loginUser.setAuthorities(authorities);
//                    loginUser.setPermissions(pers);
//                    loginUser.setSysPermission(sysPermissions);
//                    cache.putAsync(redisKey, loginUser,2,TimeUnit.MINUTES);
//                }
//            }
//        });
//    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteRole(Integer id) {

        Integer i = sysUserRoleMapper.selectCount(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, id));
        if (i > 0)
            throw new XkdException("该角色下还有未删除的员工");

        sysRoleMapper.deleteById(id);
        sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, id));
    }

    @Override
    public Page<SysRole> roleList(RoleListDto roleListDto) {
        Integer loginCompanyId = SecurityUtil.getLoginCompanyId();
        PageHelper.startPage(roleListDto.getPageNum(), roleListDto.getPageSize()).setPageSizeZero(roleListDto.getPageSizeZero());
        //去除平台超管角色
        return (Page<SysRole>) sysRoleMapper.roleList(roleListDto, loginCompanyId);
    }


}
